

#define REGISTER_OP_IMPL1(ctr, name)                         \
  static ::tensorflow::InitOnStartupMarker const register_op##ctr         \
      TF_ATTRIBUTE_UNUSED =                                               \
          TF_INIT_ON_STARTUP_IF( false || SHOULD_REGISTER_OP(name)) \
          << ::tensorflow::register_op::OpDefBuilderWrapper(name)


#define REGISTER_OP_IMPL2(ctr, name)                         \
  static ::tensorflow::InitOnStartupMarker const register_op##ctr         \
      TF_ATTRIBUTE_UNUSED =                                               \
          TF_INIT_ON_STARTUP_IF( true || SHOULD_REGISTER_OP(name)) \
          << ::tensorflow::register_op::OpDefBuilderWrapper(name)


#define REGISTER_OPx(name)        \
  TF_ATTRIBUTE_ANNOTATE("tf:op") \
  TF_NEW_ID_FOR_INIT(REGISTER_OP_IMPL1, name)
  
// REGISTER_KERNEL_BUILDER_IMPL_2, with a unique 'ctr' as the first argument.
// TODO(dodgen): There are some uses of this macro inside functions, where
// kernel_builder refers to (non-const) locals (they should be fixed). To
// accommodate those, kernel_builder.Build() appears as an argument to an
// immediately-called lambda (not in the lambda itself).
#define REGISTER_KERNEL_BUILDER_IMPL_3x(ctr, op_name, kernel_builder_expr,   \
                                       x)               \
  static ::tensorflow::InitOnStartupMarker const register_kernel_##ctr      \
      TF_ATTRIBUTE_UNUSED =                                                 \
          TF_INIT_ON_STARTUP_IF(false ||                         \
                                (SHOULD_REGISTER_OP_KERNEL(#x) && \
                                 SHOULD_REGISTER_OP(op_name)))              \
          << ([](::tensorflow::KernelDef const* kernel_def) {               \
               ::tensorflow::kernel_factory::OpKernelRegistrar registrar(   \
                   kernel_def, #x,                                \
                   [](::tensorflow::OpKernelConstruction* context)          \
                       -> ::tensorflow::OpKernel* {                         \
                     return new x(context);                       \
                   });                                                      \
               (void)registrar;                                             \
               return ::tensorflow::InitOnStartupMarker{};                  \
             })(kernel_builder_expr.Build());


#define TF_NEW_ID_FOR_INIT_2x(m, c, op_name,expr,x) m(c, op_name,expr,x)
#define TF_NEW_ID_FOR_INIT_1x(m, c, op_name,expr,x) TF_NEW_ID_FOR_INIT_2x(m, c, op_name,expr,x)

#define TF_NEW_ID_FOR_INITx(m, op_name,expr,x) \
  TF_NEW_ID_FOR_INIT_1x(m, __COUNTER__, op_name,expr,x)
  
// REGISTER_KERNEL_BUILDER_IMPL, but with kernel_builder split to op_name,
// kernel_builder_expr.
#define REGISTER_KERNEL_BUILDER_IMPL_2x(op_name, kernel_builder_expr, \
                                       x)        \
  TF_NEW_ID_FOR_INITx(REGISTER_KERNEL_BUILDER_IMPL_3x, op_name,        \
                     kernel_builder_expr, x)

#define TF_EXTRACT_KERNEL_NAME_IMPLx(m, op_name,kernel_builder,x) m(op_name,kernel_builder,x)

#define TF_EXTRACT_KERNEL_NAMEx(m, op_name,kernel_builder, x)                    \
  TF_EXTRACT_KERNEL_NAME_IMPLx(m, op_name, ::tensorflow::register_kernel::Name(op_name)##kernel_builder, \
                              x)

// REGISTER_KERNEL_BUILDER, but with is_system_kernel bound.
#define REGISTER_KERNEL_BUILDER_IMPLx(op_name,kernel_builder, x) \
  TF_EXTRACT_KERNEL_NAMEx(REGISTER_KERNEL_BUILDER_IMPL_2x, op_name,kernel_builder,    \
                         x)

#define REGISTER_KERNEL_BUILDERx(op_name,kernel_builder, x) \
  TF_ATTRIBUTE_ANNOTATE("tf:kernel")                 \
  REGISTER_KERNEL_BUILDER_IMPLx(op_name,kernel_builder, x)